/*
 * RelaisCardController.h
 *
 *  Created on: 14.05.2009
 *      Author: michael
 */

#include "RelaisCardController.h"

RelaisCardController::RelaisCardController(const char* device) : model() {

	try {
		port = new SerialComm(device);
	} catch (exception e){
		cerr << "Konnte port nicht initialisieren! " << e.what();
	}

	// ToDo: Kernel-Level-Thread zum Empfangen anlegen

	init();
}

RelaisCardController::RelaisCardController(const char* device, const RelaisCardModel& model) {

	this->model = model;

	try {
		port = new SerialComm(device);
	} catch (exception e){
		cerr << "Konnte port nicht initialisieren! " << e.what();
	}

	// ToDo: Kernel-Level-Thread zum Empfangen anlegen

	init();
}

RelaisCardController::~RelaisCardController(){
	quit();
}

void RelaisCardController::init() throw (exception){
	send(CMD_INIT,1,0);
	if (model.isEmpty())
		throw length_error(NO_CARD);
	getPort();
}

void RelaisCardController::getPort(){
	for (int i = 1; i <= model.size(); i++)
		send(CMD_GET,i,0);
}

void RelaisCardController::quit( void ){
	delete port;
//	delete model;
}

int RelaisCardController::receiving( void ){
	while (true){
		try {
			receive();
		} catch (char* s) {
			cerr << "Fehler beim Emfpangen von Daten!" << endl << s << endl;
		}
	}
	return 0;
}

void RelaisCardController::receive( void ) throw (exception) {

	// Daten von Port auslesen
	unsigned char data[DATA_LENGTH];

	try {
		port->receive(data);
	} catch (out_of_range e) {
		cerr << "Fehler beim Empfangen von Daten!" << endl << e.what();
	}

	cout << "Empfange: " << (int)data[0] << ", " << (int)data[1] << ", " << (int)data[2] << ", " << (int)data[3] << endl;

	// Checksumme pruefen
	if (data[3] != buildCRC(data[0], data[1], data[2]))
		throw logic_error(FALSE_CHECKSUM);

	// Antwortbefehl auswerten
	switch (data[0]) {
	case CMD_INIT:
		cout << "Init-Loop erhalten! Alle Karten Instanzieriert!" << endl;
		break;
	case GET_INIT:	// Karte gibt positive Initabfrage zurueck
		cout << "Initialisierungsantwort von Karte " << (int)data[1] << " erhalten!" << endl;
		model.addCard();
		// ToDo: Solange kein Empfangsthread hier rekursiv arbeiten
		// da bei Initialisierung mehrerer Karten zuletzt SET_INIT zurückgegeben wird
		receive();
		break;
	case GET_SET:
	case GET_GET:
		model.setCard(data[1], data[2]);
		cout << "Schaltbefehl quittiert (KARTE: " << (int)data[1] << ", WERT: " << (int)data[2] << ")" << endl;
		break;
	default:
		break;
	}
}

unsigned char RelaisCardController::buildCRC(unsigned char cmd1, unsigned char cmd2, unsigned char cmd3){
	return cmd1 ^ cmd2 ^ cmd3;
}

int RelaisCardController::send(unsigned char command, unsigned char card_nr, unsigned char value){

	unsigned char data[4] = {command, card_nr, value, NULL};
	data[3] = buildCRC(data[0], data[1], data[2]);

	try{
		port->send(data);
	} catch (out_of_range e) {
		cerr << "Fehler beim Senden von Daten!" << endl << e.what();
	}

	cout << "Sende: " << (int)data[0] << ", " << (int)data[1] << ", " << (int)data[2] << ", " << (int)data[3] << endl;
	// ToDo: Wenn Empfangsthread hier kein receive() mehr nötig!
	receive();
	return 0;
}

void RelaisCardController::print( void ){
	cout << model.toString() << endl;
}

void RelaisCardController::setRelais(unsigned char card, unsigned char relais, bool flag){
	try {
		// Überprüfen ob Relais bereits gesetzt
		if (model.isSet(card, relais) == flag)
			cerr << "Relais " << (int)relais << " der Karte " << (int)card << " bereits auf " << flag << endl;

		// Neuen Wert der Karte ermitteln
		unsigned char curValue = model.getCard(card);
		unsigned char newValue = 0;
		if (flag)
			// Die Bitoperation setzt das Bit des Relais
			newValue = curValue | model.getRelaisValue(relais);
		else
			// Die Bitoperation laesst alle Bits, bis auf das Bit des Relais, gesetzt
			newValue = curValue & ~model.getRelaisValue(relais);

		// Kommando an Karte senden
		send(CMD_SET,card,newValue);

	} catch (out_of_range e) {
		cerr << "Konnte auf Relaiskarte " << (int)card << " nicht zugreifen. (" << __FUNCTION__ << ")" << endl << e.what();
	} catch (exception e){
		cerr << "Relais " << (int)relais << " an Karte " << (int)card << " bereits auf " << flag << endl;
	}
}

